#ifndef clox_value_h
#define clox_value_h

#include "common.h"
typedef struct Obj Obj;
typedef struct ObjString ObjString;
typedef enum {
    VAL_BOOL,
    VAL_NIL,
    VAL_NUMBER,
    // 代指所有堆分配的类型
    VAL_OBJ
} ValueType;
typedef struct {
    ValueType type;
    union {
        bool boolean;
        double number;
        // 堆中的对象
        Obj* obj;
    } as;
} Value;

// 18.2 Lox值和C值
// 除非我们知道Value包含适当的类型，否则使用任何的AS_宏都是不安全的。为此，我们定义最后几个宏来检查Value的类型。
#define IS_BOOL(value) ((value).type == VAL_BOOL)
#define IS_NIL(value) ((value).type == VAL_NIL)
// 19.1 值与对象
#define IS_OBJ(value) ((value).type == VAL_OBJ)
#define AS_OBJ(value) ((value).as.obj)
#define IS_NUMBER(value) ((value).type == VAL_NUMBER)
// 但是为了能对Value做任何操作，我们需要将其拆包并取出对应的C值
#define AS_BOOL(value)  ((value).as.boolean)
#define AS_NUMBER(value) ((value).as.number)
// 我们会用少量的宏来实现这些转换，每个宏对应一个类型和操作。首先，将原生的C值转换为clox Value
#define BOOL_VAL(value) ((Value) {VAL_BOOL, {.boolean = value}})
#define NIL_VAL ((Value) {VAL_NIL, {.number = 0}})
#define NUMBER_VAL(value) ((Value) {VAL_NUMBER, {.number = value}})
#define OBJ_VAL(object) ((Value){VAL_OBJ, {.obj = (Obj*)object}})
// 值数组,表示常量池
typedef struct {
    int capacity;
    int count;
    Value* values;
} ValueArray;

bool valuesEqual(Value a, Value b);
void initValueArray(ValueArray* array);
void writeValueArray(ValueArray* array, Value value);
void freeValueArray(ValueArray* array);
void printValue(Value value);

#endif